package service

import (
	"errors"
	"time"

	"pbj-server/internal/model"
	"pbj-server/pkg/database"
	"pbj-server/pkg/jwt"
	"pbj-server/pkg/logger"
	"pbj-server/pkg/sms"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

// UserService 用户服务
type UserService struct{}

// NewUserService 创建用户服务实例
func NewUserService() *UserService {
	return &UserService{}
}

// Register 用户注册
func (s *UserService) Register(req *model.UserRegisterRequest) error {
	// 验证手机号格式
	if !sms.IsPhoneValid(req.Phone) {
		return errors.New("手机号格式不正确")
	}
	
	// 验证验证码
	valid, err := sms.VerifyCode(req.Phone, req.Code)
	if err != nil {
		return err
	}
	if !valid {
		return errors.New("验证码错误或已过期")
	}
	
	// 检查用户名是否已存在
	var existingUser model.User
	if err := database.GetDB().Where("username = ?", req.Username).First(&existingUser).Error; err == nil {
		return errors.New("用户名已存在")
	}
	
	// 检查邮箱是否已存在
	if err := database.GetDB().Where("email = ?", req.Email).First(&existingUser).Error; err == nil {
		return errors.New("邮箱已存在")
	}
	
	// 检查手机号是否已存在
	if err := database.GetDB().Where("phone = ?", req.Phone).First(&existingUser).Error; err == nil {
		return errors.New("手机号已存在")
	}
	
	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		logger.Errorf("密码加密失败: %v", err)
		return errors.New("密码加密失败")
	}
	
	// 创建用户
	user := model.User{
		Username: req.Username,
		Email:    req.Email,
		Phone:    req.Phone,
		Password: string(hashedPassword),
		Nickname: req.Nickname,
		Role:     "user",
		Status:   1,
	}
	
	if err := database.GetDB().Create(&user).Error; err != nil {
		logger.Errorf("创建用户失败: %v", err)
		return errors.New("创建用户失败")
	}
	
	logger.Infof("用户注册成功: %s", req.Username)
	return nil
}

// Login 用户登录
func (s *UserService) Login(req *model.UserLoginRequest) (*model.UserLoginResponse, error) {
	var user model.User
	
	// 根据用户名、邮箱或手机号查找用户
	if err := database.GetDB().Where("username = ? OR email = ? OR phone = ?", 
		req.Username, req.Username, req.Username).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, err
	}
	
	// 检查用户状态
	if user.Status != 1 {
		return nil, errors.New("用户已被禁用")
	}
	
	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		return nil, errors.New("密码错误")
	}
	
	// 更新最后登录时间
	now := time.Now()
	if err := database.GetDB().Model(&user).Update("last_login", &now).Error; err != nil {
		logger.Warnf("更新最后登录时间失败: %v", err)
	}
	
	// 生成JWT令牌
	token, err := jwt.GenerateToken(user.ID, user.Username, user.Role)
	if err != nil {
		logger.Errorf("生成JWT令牌失败: %v", err)
		return nil, errors.New("生成令牌失败")
	}
	
	logger.Infof("用户登录成功: %s", user.Username)
	
	return &model.UserLoginResponse{
		Token: token,
		User:  user,
	}, nil
}

// GetProfile 获取用户资料
func (s *UserService) GetProfile(userID uint) (*model.UserProfileResponse, error) {
	var user model.User
	
	if err := database.GetDB().First(&user, userID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, err
	}
	
	response := user.ToProfileResponse()
	return &response, nil
}

// UpdateProfile 更新用户资料
func (s *UserService) UpdateProfile(userID uint, req *model.UserUpdateRequest) error {
	updates := make(map[string]interface{})
	
	if req.Nickname != "" {
		updates["nickname"] = req.Nickname
	}
	if req.Avatar != "" {
		updates["avatar"] = req.Avatar
	}
	
	if len(updates) == 0 {
		return errors.New("没有需要更新的字段")
	}
	
	if err := database.GetDB().Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		logger.Errorf("更新用户资料失败: %v", err)
		return errors.New("更新用户资料失败")
	}
	
	logger.Infof("用户资料更新成功: %d", userID)
	return nil
}

// GetAllUsers 获取所有用户（管理员功能）
func (s *UserService) GetAllUsers(page, pageSize int) (*model.UserListResponse, error) {
	var users []model.User
	var total int64
	
	// 获取总数
	if err := database.GetDB().Model(&model.User{}).Count(&total).Error; err != nil {
		return nil, err
	}
	
	// 分页查询
	offset := (page - 1) * pageSize
	if err := database.GetDB().Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
		return nil, err
	}
	
	// 转换为响应格式
	var userResponses []model.UserProfileResponse
	for _, user := range users {
		userResponses = append(userResponses, user.ToProfileResponse())
	}
	
	return &model.UserListResponse{
		Total: total,
		Users: userResponses,
	}, nil
}

// GetUserByID 根据ID获取用户（管理员功能）
func (s *UserService) GetUserByID(userID uint) (*model.UserProfileResponse, error) {
	var user model.User
	
	if err := database.GetDB().First(&user, userID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, err
	}
	
	response := user.ToProfileResponse()
	return &response, nil
}

// UpdateUser 更新用户（管理员功能）
func (s *UserService) UpdateUser(userID uint, updates map[string]interface{}) error {
	if err := database.GetDB().Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
		logger.Errorf("更新用户失败: %v", err)
		return errors.New("更新用户失败")
	}
	
	logger.Infof("管理员更新用户成功: %d", userID)
	return nil
}

// DeleteUser 删除用户（管理员功能）
func (s *UserService) DeleteUser(userID uint) error {
	if err := database.GetDB().Delete(&model.User{}, userID).Error; err != nil {
		logger.Errorf("删除用户失败: %v", err)
		return errors.New("删除用户失败")
	}
	
	logger.Infof("管理员删除用户成功: %d", userID)
	return nil
}

// ChangePassword 修改密码
func (s *UserService) ChangePassword(userID uint, oldPassword, newPassword string) error {
	var user model.User
	
	if err := database.GetDB().First(&user, userID).Error; err != nil {
		return errors.New("用户不存在")
	}
	
	// 验证旧密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)); err != nil {
		return errors.New("旧密码错误")
	}
	
	// 加密新密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		logger.Errorf("密码加密失败: %v", err)
		return errors.New("密码加密失败")
	}
	
	// 更新密码
	if err := database.GetDB().Model(&user).Update("password", string(hashedPassword)).Error; err != nil {
		logger.Errorf("更新密码失败: %v", err)
		return errors.New("更新密码失败")
	}
	
	logger.Infof("用户修改密码成功: %d", userID)
	return nil
} 